package com.blood.redis.config;


import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;

import javax.annotation.Resource;
import java.io.Serializable;
import java.time.Duration;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.TimeUnit;

/**
 * @author daoren
 * @ClassName: RedisUtil
 * @Description: TODO redis管理工具
 */
@Configuration
@SuppressWarnings("unchecked")
public class RedisUtil {
    /**
     * .
     */
    private RedisTemplate redisTemplate;


    @Resource
    public void setRedisTemplate(RedisTemplate<String, Object> redisTemplate) {
        redisTemplate.setKeySerializer(new StringRedisSerializer());
        redisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer());
        this.redisTemplate = redisTemplate;
    }

    /**
     * 批量删除对应的value.
     *
     * @param keys keys
     */
    public void remove(final String... keys) {
        for (String key : keys) {
            remove(key);
        }
    }

    /**
     * 批量删除key.
     *
     * @param pattern pattern
     */
    @SuppressWarnings("unchecked")
    public void removePattern(final String pattern) {
        Set<Serializable> keys = redisTemplate.keys(pattern);
        if (keys.size() > 0) {
            //迭代遍历
            Iterator<Serializable> it = keys.iterator();
            Set<Serializable> keyAll = new HashSet<>();
            while (it.hasNext()) {
                keyAll.add(String.valueOf(it.next()));
            }
            redisTemplate.delete(keyAll);
        }
    }

    /**
     * 删除对应的value.
     *
     * @param key key
     */
    @SuppressWarnings("unchecked")
    public void remove(final String key) {
        if (exists(key)) {
            redisTemplate.delete(key);
        }
    }

    /**
     * 删除对应的value.
     *
     * @param keys list
     */
    @SuppressWarnings("unchecked")
    public void remove(Collection<String> keys) {
        Collection<String> keyAll = new LinkedList<>();
        if (keys.size() > 0) {
            for (String str : keys) {
                keyAll.add(str);
            }
        }
        redisTemplate.delete(keyAll);
    }

    /**
     * 判断缓存中是否有对应的value.
     *
     * @param key key
     * @return boolean
     */
    @SuppressWarnings("unchecked")
    public boolean exists(final String key) {
        return redisTemplate.hasKey(key);
    }


    /**
     * 读取缓存.
     *
     * @param key key
     * @return Object
     */
    public Object get(final String key) {
        Object result = null;
        ValueOperations<Serializable, Object> operations = redisTemplate.opsForValue();
        result = operations.get(key);
        return result;
    }

    /**
     * 写入缓存.
     *
     * @param key   key
     * @param value value
     * @return boolean
     */
    public boolean set(final String key, Object value) {
        boolean result = false;
        try {
            ValueOperations<Serializable, Object> operations = redisTemplate.opsForValue();
            operations.set(key, value);
            result = true;
        } catch (Exception e) {
            throw new RuntimeException(e.getMessage());
        }
        return result;
    }

    /**
     * 写入缓存.
     *
     * @param key        key
     * @param value      value
     * @param expireTime expireTime
     * @return boolean
     */
    public boolean set(final String key, Object value, Long expireTime) {
        boolean result = false;
        try {
            ValueOperations<Serializable, Object> operations = redisTemplate.opsForValue();
            operations.set(key, value);
            redisTemplate.expire(key, expireTime, TimeUnit.SECONDS);
            result = true;
        } catch (Exception e) {
            throw new RuntimeException(e.getMessage());
        }
        return result;
    }

    /**
     * @param key key
     * @return Long
     */
    public Long increment(final String key) {
        Long result = null;
        try {
            ValueOperations<Serializable, Object> operations = redisTemplate.opsForValue();
            result = operations.increment(key);

        } catch (Exception e) {
            result = null;
        }
        return result;
    }

    /**
     * @param key   key
     * @param delta delta
     * @return Long
     */
    public Long increment(final String key, final long delta) {
        Long result = null;
        try {
            ValueOperations<Serializable, Object> operations = redisTemplate.opsForValue();
            result = operations.increment(key, delta);

        } catch (Exception e) {
            result = null;
        }
        return result;
    }

    /**
     * @param key   key
     * @param delta delta
     * @return Long
     */
    public Long incrementExist(final String key, final long delta) {
        if (exists(key)) {
            return increment(key, delta);
        }
        return null;
    }

    /**
     * @param key        key
     * @param expireTime expireTime
     * @return boolean
     */
    public boolean expireTime(final String key, Long expireTime) {
        boolean bool = false;
        try {
            Boolean b = redisTemplate.expire(key, expireTime, TimeUnit.SECONDS);
            if (null != b && b.booleanValue()) {
                bool = b.booleanValue();
            } else {
                bool = false;
            }
        } catch (Exception e) {
            bool = false;
        }
        return bool;
    }

    /**
     * 如果密钥不存在，则设置密钥以保持字符串值和到期超时.
     *
     * @param key     键
     * @param value   值
     * @param exptime 有效时间秒
     * @return boolean
     */
    public boolean setNX(final String key, final Serializable value, final long exptime) {
        try {
            ValueOperations<Serializable, Object> operations = redisTemplate.opsForValue();
            return Optional.ofNullable(operations.setIfAbsent(key, value, Duration.ofSeconds(exptime))).orElse(false);
        } catch (Exception e) {
            return false;
        }
    }
}
